-- author: zmf96
-- date: 2019/01/28 12:00
-- vsrsion: lua5.1 

-- 这是lua中的单行注释
--[[
    这是多行注释,
    多行注释还是比较方便的 
--]]

print("hello world") -- 喜闻乐见的hello world

--[[
    标识符：
    标示符以一个字母 A 到 Z 或 a 到 z 或下划线 _ 开头后加上0个或多个字母，
    下划线，数字（0到9）。

    最好不要使用下划线加大写字母的标示符，因为Lua的保留字也是这样的。

    一般约定，以下划线开头连接一串大写字母的名字（比如 _VERSION）被保留用于 
    Lua 内部全局变量。

    lua中的关键字：and	break	do	else elseif	end	false for function	
                  if in	local nil not	or	repeat
                  return	then	true	until while
--]]

-- 数据类型
print(type("Hello world"))      --> string
print(type(42))
print(type(10.4*3))             --> number
print(type(print))              --> function
print(type(type))               --> function
print(type(true))               --> boolean
print(type(nil))                --> nil
print(type(type(X)))            --> string

local tbl2 = {"apple", "pear", "orange", "grape"}
print(type(tbl2))

-- lua raw string
print([[raw stirng \r\n]])
print([[^\d+.\d+$]])

-- lua里的字符串都是不可以修改的（只读），不能像C/C++那样单独访问或者修改字符串里的某个字符

-- 变量
x = 1 -- 定义一个全局变量x,赋值为1，全局可见
local str = 'this is str' -- 定义一个局部变量str，仅此文件可见

do                      -- 开始一个代码块
    local pai = 3.14    -- 局部变量pia，仅在此代码块内可见
end                     -- 代码块结束

print(type(pai))        --局部变量pai消失，访问的是全局变量pai,一个变量如果没有显式赋值，那么它的值就是nil

-- lua里应该尽量少使用全局变量，多使用局部变量，局部变量不仅很好地的控制了变量的作用域，避免全局名字冲突，
-- 而且因为“局部化” ，解释器查找的速度更快。 

-- 运算符
print(1 + 1, ",", 5-3) -- 加 减
print(2*4,",",1/3)      -- 乘 除
print(5%2,",", 3^3)     -- 取模 幂运算
count = 10      
count = count + 1  -- 类似于其他语言中的 ++count 

print(3.14 > 2.712) -- 大于
print(1/3 == 2/6)   -- 等于
print('10' ~= 10)   -- 不等，注意： ~= 不是 !=

print(tonumber('10') == 10 ) -- 等于
print(tostring(10) == '10') -- 等于

-- lua中nil和false认为是假，其他都是真，包括数据0
-- a and b, 如果 a 是真，返回b,否则返回a
-- a or b, 与 and操作相反， 如果a是真，返回a,否则返回b
print(0 and 'abc') -- 0 是真，所以返回字符串'abc'
print( y or 123)   -- y是全局变量，值是nil，返回 100
print(not y)  -- y是全局变量，值是nil，返回 true 
local x = y or 100 -- 为 x 赋初值， y不存在则默认值是100
local y = a and b or c  -- 相当于 a?b:c ,由 a的真假决定赋值b或c
print(x,y) 

print(#"hello lua") -- 计算字符串长度 输出 9
print("hello" .. "world") -- 连接两个字符串  输出 helloworlc
x = nil 
print(1 + (x or 2)) -- x 不存在则使用2执行加法操作   输出 3
print("msg is ".. (x or '-')) -- x 不存在则使 '-' 执行连接运算  输出 msg is -

-- 语句
-- 赋值语句
local data, err     -- 声明了两个局部变量，默认值都是nil
local a, b = 1, 'lua' -- a、b分别复制为数字1和字符串'lua'
local x, y = a, b, 'not_used' -- x，y分别赋值为a和b, 第三个字符串未使用
local m, n = "only this"    -- m 被赋值为字符串， n没有被赋值，所以是nil
-- 语句块
do                      -- 开始一个语句块
    local x = 19        -- 一个局部变量x，仅在本块内有用
    print("x = ", x)    -- 输出变量的值
end                     -- 语句块结束
-- -- 条件判断语句
-- if conditions then 
--     ...
-- elseif conditions then
--     ...
-- else 
--     ...
-- end 
-- -- while/until循环语句
-- while conditions do 
--     ...
-- end 

-- repeat
--     ...
-- until conditions  -- 条件成立时退出循环
-- for循环语句
for var=1,5,0.5 do  -- for var=m,n,step do
    print("for : ", var)
end 

-- 函数
local function fun1(a,b,c)
    return a .. (b or '') .. (c or '')
end
print(fun1(1,2,3))
print(fun1(1,2)) -- 少的参数默认值为nil

local function fun2(a,b)
    return a + b, a * b -- return返回多个返回值
end
local x, y = fun2(2,3) -- 使用赋值语句接收返回的多个结果

-- 表
local a = {"abc","efg","xyz"}
for i,v in ipairs(a) do 
    print(a[i], ', ')
end

for k,v in pairs(a) do 
    print(k, ' => ', v)
end

-- 模块
-- lua中的模块就是一个函数库，实际就是一个lua表，里面有模块作者提供的各种功能函数，可以用点号 '.'访问。
-- local proto = {     -- 定义一个表，包含模块所有功能
--     version = '0.1' -- 给一个基本的版本号信息
-- }

-- function proto.run()  -- 定义一个函数，注意不能是local
--     print("run is mod") -- 函数体
-- end                   -- 函数定义结束

-- return proto    -- 返回模块的表

-- luajit 扩展实现了goto语句
for i = 1,10 do 
    if i % 2 == 0 then 
        goto continue
    end
    print("i = ",i)

    ::continue::
end

-- -- luajit扩展 bit
-- -- luajit bit模块提供位运算功能
-- local bit = require "bit"

-- local band, bor = bit.band, bit.bor 
-- local bxor, bnot = bit.bxor, bit.bnot
-- local blshift,brshift  = bit.lshift,bit.brshift
-- local bohex = bit.tohex

-- local x, y = 1,4
-- print(band(x,y))  -- 1 & 4 = 0
-- print(bor(x,y)) -- 1|4 = 5
-- print(bxor(x,y))  -- 1 ^ 4 = 5
-- print(tohex(bnot(x))) -- ~1 = fffffffe
-- print(blshift(y,1))  -- 4 << 1= 8

-- -- 使用bit库配合string.byte可以较容易地解析二进制数据
-- local byte = string.byte
-- local data = "\000\000\001\001"

-- local x = blshift(a,24) + blshift(b,16) + blshift(c, 8) + d  -- 第一个字节左移24位 第二个字节左移16
-- print(x)

-- luaJIT ffi 
-- 极大的简化了lua代码里调用c/c++函数的工作，而且执行效率更高
local ffi = require "ffi"

local ffi_null = ffi.ffi_null
local ffi_cdef = ffi.cdef 
local ffi_new = ffi.new
local ffi_C = ffi.C
local ffi_typeof = ffi.typeof
ffi_cdef[[
    struct timeval {
        long int tv_sec;
        long int tv_usec;
    };
    int gettimeofday(struct timeval *tv, void *tz); // c函数声明
]]

local timeval_t = ffi_typeof("struct timeval")  -- 产生一个C结构的“类型对象”
local tm = ffi_new(timeval_t)           -- 分配供C函数使用的内存

ffi_C.gettimeofday(tm,ffi_null)

print(type(tm.tv_sec))  -- 查看数据类型，是cdata  cdata
print("Sec:",tm.tv_sec) -- Sec:	1548666799LL
print("Sec:", tonumber(tm.tv_sec)) -- Sec:	1548666799